# -*- coding: utf-8 -*-
"""
aimfc.py - 目标函数demo
描述:
    Geatpy的目标函数遵循本案例的定义方法，传入种群表现型矩阵Phen，以及可行性列向量LegV
    若没有约束条件，也需要返回LegV
    若要改变目标函数的输入参数、输出参数的格式，则需要修改或自定义算法模板
"""

import numpy as np

def aimfuc(Chrom,LegV):
    x1 = Chrom[:, [0]]
    x2 = Chrom[:, [1]]
    x3 = Chrom[:, [2]]
    x4 = Chrom[:, [3]]
    x5 = Chrom[:, [4]]
    ObjV1 = -25 * (x1 - 2)**2 - (x2 - 2)**2 - (x3 - 1)**2 - (x4 - 4)**2 - (x5 - 1)**2
    ObjV2 = (x1 - 1)**2 + (x2 - 1)**2 + (x3 - 1)**2 + (x4 - 1)**2 + (x5 - 1)**2
    # 约束条件
    idx1 = np.where(x1 + x2 < 2)[0]
    idx2 = np.where(x1 + x2 > 6)[0]
    idx3 = np.where(x1 - x2 < -2)[0]
    idx4 = np.where(x1 - 3*x2 > 2)[0]
    idx5 = np.where(4 - (x3 - 3)**2 - x4 < 0)[0]
    idx6 = np.where((x5 - 3)**2 + x4 - 4 < 0)[0]
    exIdx = np.unique(np.hstack([idx1, idx2, idx3, idx4, idx5, idx6])) # 得到非可行解的下标
    # 惩罚非可行解方法1：修改非可行个体的目标函数值的方法，对非可行解对应的目标函数值作出惩罚，而不标记其为非可行解
    # 不标记非可行解的做法比较危险，假如处理不慎，可能会导致以下错误情况：
    # 某一代的种群全是非可行解而其组成的“不合法的帕累托最优解集”恰好支配了其他所有的可行解。
    # 此时进化记录器会受到欺骗，而得出一个实际上是非可行解的搜索结果。
    # 一个比较好的处理方法是：要让其绝对地比其他任何可行解的目标函数值都要大或小（看是最小化目标还是最大化目标）。
#    ObjV1[exIdx] = np.max(ObjV1) # 此处修改成max(ObjV1)是危险的，因为无法保证修改后能被其他可行解支配
#    ObjV2[exIdx] = np.max(ObjV2)
    
    # 惩罚非可行解的方法2：修改非可行个体的适应度的方法，配合punishing罚函数接口，先标记非可行解，然后在punishing中对其适应度FitnV作出惩罚
    # (也可以不写punishing，因为算法模板中在一些与适应度有关的计算时已传入LegV，此时内核函数会自动处理非可行解的适应度)
    # (写punishing实质上是进一步惩罚非可行解的适应度值)
    LegV[exIdx] = 0 # 标记非可行解对应的可行性列向量中元素的值为0
    
    return [np.hstack([ObjV1, ObjV2]), LegV]
    